import React, {Component} from 'react';
import CanvasSvg from "./canvasSVG";
import {getFibTree, getTree} from "./fib";
import Menu from "./menu";
import Navbar from "./navbar";
import Details from "./details";
import {MinHeap} from "./Heap";
import $ from "jquery"
import {xBias, xTimes, yBias, yTimes} from "./Const";


let tree;

class Graph extends Component {
    constructor() {
        super();
        this.state = {
            root:undefined,
            reset: false,
            vertices:[],
            edges:[],
            current:-1,
            n:0,
            r:2,
            nrFlag:true,
            redNumber: -1,
            algo:0,
            offset:0,
            animation_stop: true,
            time: 500,
            leftMost: undefined,
            rightMost: undefined
        }
        this.input = [];
        this.inputKey = 0;
    }
    // setNumber = (event)=>{
    //     let value = event.target.valueAsNumber;
    //     if(value!== NaN && value<99)
    //         this.setState({inputNumber:value});
    //
    //     // document
    // }


    handleSpeed = (speed) => {
        let time = 900 - 8 * speed;
        this.setState({time})
    }

    onReset = () => {

        this.setState({reset: true,
                            });
        this.setState({vertices: [], edges: []})
        this.state.vertices = [];

    }

    // 执行去除tab和空格的操作
    clearPure = (string) => {
        let final = "";
        for (let i = 0; i < string.length; i++) {
            if (string[i] !== " " || string[i] !== "\t")
                final += string[i];
        }
        return final;
    }

    clearTabSpace = (string) => {
        let final = this.clearPure(string);
        return final.split(",").map((value) => parseInt(value));
    }

    sort = (string) => {
        return string.sort((a,b) => a-b);
    }

    handleInput = () => {
        if (this.state.algo != 0) {
            let inputElement = document.getElementById("input");
            let input = this.sort(this.clearTabSpace(inputElement.value));
            inputElement.value = input;
            this.input = input;
        }

    }

    handleInputKey = () => {
        if (this.state.algo != 0) {
            let inputKey = parseInt(this.clearPure(document.getElementById("input-key").value));
        // let inputKey = document.getElementById("input-key").value;
            this.inputKey = inputKey;
        }

    }

    setAlgo = (pos, val) => {
        if (pos === 0) {
            this.setState({algo: val, nrFlag: val === 0});
        }
    }

    setN = (pos, val) => {
        if (pos === 0) {
            this.setState({n: val});
        }
    }

    setR = (pos, val) => {
        if (pos === 0) {
            this.setState({r: val});
        }
    }
    addNumber = async ()=>{
        this.setState({redNumber: -1});
        this.onReset();
        //
        if (this.state.reset) {
            this.onReset();
            await this.addNumberTemp();
        }
        //
        await this.addNumberTemp();
    }

    transForDraw = (tree, rootBias) => {
        tree.x = (tree.x - rootBias) * xTimes + xBias;
        tree.y = tree.y * yTimes + yBias;
        for (let t of tree.children) {
            this.transForDraw(t, rootBias);
        }
    }

    addNumberTemp = async () => {
            this.handleInput();
            this.handleInputKey();

            // if (!this.state.animation_stop)
            //     await sleep(3000);
            if (this.state.animation_stop) {
                this.setState({ animation_stop: true});
            tree = getTree(this.state.n,this.state.algo,this.state.r, [...this.input], this.inputKey);
            this.transForDraw(tree, tree.x);
            console.log("root");
            console.log(tree);

            this.setState({leftMost: tree.getMostLeft(tree), rightMost: tree.getMostRight(tree)});

            console.log("leftMost");
            console.log(tree.getMostLeft(tree));
            console.log("rightMost");
            console.log(tree.getMostRight(tree));

            this.setState({edges:[],vertices:[], offset:tree.x, reset: false, animation_stop:false});
            this.state.vertices = [];
            // this.setState({});
                if (this.state.algo === 2) {
                     await this.recurHuffman(tree);
                } else if (this.state.algo === 1) {
                  await this.recurIfElse(tree);
                } else {
                    await this.recur(tree,undefined);

                }

            this.setState({animation_stop: true});

            }
    }

    // 这里出现bug的原因是 节点顺序设置错误
    recurHuffmanDraw = async (tree1, tree2, visited) => {

        if (!this.state.reset) {
            let parent = tree1.parent;
            let treeList = [tree1, tree2];
            let vertices = [...this.state.vertices];
            for (let i = 0; i < treeList.length; i++) {
                let current = treeList[i].getId();
                if (!visited[current]) {
                    vertices.push({label:treeList[i].tree.label.split(",")[0],val:0,
                        x:treeList[i].x,y:treeList[i].y,px:treeList[i].x,py:treeList[i].y});
                    visited[treeList[i].getId()] = true;
                    if (this.state.reset) return false;this.setState({vertices});

                }
                    if (this.state.reset) return false;this.setState({vertices, current});
                    await sleep(this.state.time);
            }

            for (let i = 0; i < treeList.length; i++) {
                let edges = this.state.edges;
                edges.push({
                    x1: treeList[i].x,
                    y1: treeList[i].y,
                    x2: parent.x,
                    y2: parent.y
                });
                if (this.state.reset) return false;this.setState({edges});
            }

            if (!visited[parent.id]) {
                vertices.push({label:parent.tree.label.split(",")[0],val:0,
                        x:parent.x,y:parent.y,px:parent.x,py:parent.y});
                    visited[parent.getId()] = true;
                    if (this.state.reset) return false;this.setState({vertices});
            }
            let current = parent.id;
            if (this.state.reset) return false;this.setState({vertices, current});
            await sleep(this.state.time);
        }
        return true;
    }

    recurHuffman = async (node) => {
        try {

            let treeHeap = new MinHeap();
            let queue = [];
            queue.push(node);

            while (!this.state.reset && queue.length !== 0) {
                let [head] = queue.splice(0, 1);
                treeHeap.insert(head);
                for (let i = 0; i < head.children.length; i++) {
                    queue.push(head.children[i]);
                }
            }

            let heap = [...treeHeap.getAll()];
            let visited = {}
            for (let i = 0; !this.state.reset && i < heap.length; i++) {
                visited[heap[i].getId()] = false;
            }

            let flag = true;
            while (!this.state.reset && flag && treeHeap.getLength() !== 1) {
                let tree1 = treeHeap.pop();
                let tree2 = treeHeap.pop();

                await (flag = this.recurHuffmanDraw(tree1, tree2, visited));
            }
            if (flag ) {
                let vertices = [...this.state.vertices];
                let parent = treeHeap.peek();
                vertices.push({label:parent.tree.label.split(",")[0],val:0,
                        x:parent.x,y:parent.y,px:parent.x,py:parent.y});
             !this.state.reset && this.setState({vertices});
            }
        } catch (e) {
        }

    }

    recurIfElseDraw = async (node, key) => {
        if (!this.state.reset) {
            let nowCondition = parseInt(node.tree.label.substring(1));

        // 处理本轮的情况
        // 先访问当前节点
        let vertices = this.state.vertices;
        let parent = node.parent;
        let current = vertices.length;
        if (!parent) {
            vertices.push({label: node.tree.label, val: node.tree.node, x:node.x,y:node.y,px:node.x,py:node.y});
            !this.state.reset && this.setState({vertices,current});
        }
        await sleep(this.state.time);
        let edges = this.state.edges;
        let nodeCurrent = current;


        for (let i = 0; i < node.children.length; i++) {
            current = vertices.length;
            edges.push({
                x1:node.x,
                y1:node.y,
                x2:node.children[i].x,
                y2:node.children[i].y
            });
            !this.state.reset && this.setState({edges});

            vertices.push({label: node.children[i].tree.label, val: node.tree.node,
                x:node.children[i].x,y:node.children[i].y,px:node.x,py:node.y});
            !this.state.reset && this.setState({vertices, current});
            await sleep(this.state.time);
            if (i !== node.children.length - 1) {
                if (key < nowCondition) {
                    return;
                }
                let redNumber = current ;
                !this.state.reset && this.setState({vertices, redNumber});
                await sleep(this.state.time);
                // 回到父节点
                current = nodeCurrent;
                !this.state.reset && this.setState({vertices, current});
            } else {
                if (!node.children[i].children.length) {
                    return;
                }
                await this.recurIfElseDraw(node.children[i], key);
            }
        }
        }
    }


    recurIfElse = async (node) => {
        try {
            let key = this.inputKey;
            await this.recurIfElseDraw(node, key);
        } catch {}
    }

    recur2 = async (node, parent) => {
        let vertices = this.state.vertices;
        let current = this.state.vertices.length;
        try {

        if (!this.state.reset) {

            if (node.children.length > 0) {
                !this.state.reset && await this.recur2(node.children[0], node);
                !this.state.reset && this.setState({current});
                if (node.children.length > 1) {
                    !this.state.reset && await this.recur2(node.children[1], node);
                    !this.state.reset && this.setState({current});
                }

            }

         if( parent!==undefined ){
            if( node.children.length ) {
                for (let i = 0; i < node.children.length; i++) {
                    let edges = this.state.edges;
                    edges.push({
                    x1:node.children[i].x,
                    y1:node.children[i].y,
                    x2:node.x,
                    y2:node.y
                    });
                !this.state.reset && this.setState({edges});
                }
                vertices.push({label:node.tree.label,val:0,x:node.x,y:node.y,px:node.x,py:node.y});

            }
            else
                vertices.push({label:node.tree.label,val:node.tree.node,x:node.x,y:node.y,px:node.x,py:node.y});
            !this.state.reset && this.setState({vertices,current});


        }else {
            if( node.children.length ) {
             for (let i = 0; i < node.children.length; i++) {
                    let edges = this.state.edges;
                    edges.push({
                    x1:node.children[i].x,
                    y1:node.children[i].y,
                    x2:node.x,
                    y2:node.y
                    });
                !this.state.reset && this.setState({edges});
                }
                vertices.push({label:node.tree.label,val:0,x:node.x,y:node.y,px:node.x,py:node.y});

            }
            else
                vertices.push({label:node.tree.label,val:node.tree.node,x:node.x,y:node.y,px:node.x,py:node.y});
            !this.state.reset && this.setState({vertices,current});
        }
        await sleep(this.state.time);

        }}
        catch (e) {
        }

    }

    recur = async (node,parent)=>{
        try {
            let vertices = this.state.vertices;
        let current = this.state.vertices.length;

        if (!this.state.reset) {
             if( parent!==undefined ){
            if( node.children.length )
                vertices.push({label:node.tree.label,val:0,x:node.x,y:node.y,px:parent.x,py:parent.y});
            else
                vertices.push({label:node.tree.label,val:node.tree.node,x:node.x,y:node.y,px:parent.x,py:parent.y});
            !this.state.reset && this.setState({vertices,current});

            let edges = this.state.edges;
            edges.push({
                x1:parent.x,
                y1:parent.y,
                x2:node.x,
                y2:node.y
            });
            !this.state.reset && this.setState({edges});
        }else{
            if( node.children.length )
                vertices.push({label:node.tree.label,val:0,x:node.x,y:node.y,px:node.x,py:node.y});
            else
                vertices.push({label:node.tree.label,val:node.tree.node,x:node.x,y:node.y,px:node.x,py:node.y});
            !this.state.reset && this.setState({vertices,current});
        }
        await sleep(this.state.time);


        for(let i=0;i<node.children.length;i++){
            !this.state.reset &&  await this.recur( node.children[i], node);

            !this.state.reset && this.setState({current});
            !this.state.reset && await sleep(this.state.time);
        }
        let verticess = [...this.state.vertices];
        verticess[current].val=node.tree.node;
        !this.state.reset && this.setState({vertices:verticess});

        }


        }
        catch (e) {
        }
        
    }
    render = () =>  {
        // $('body').css({"overflow-x": "hidden"});
        return (
            <div style={{
                overflowX: "hidden"}}>
                <Navbar/>
                <Menu
                    algo={this.state.algo}
                    handleSpeed = {this.handleSpeed}
                    setN={this.setN}
                    setR={this.setR}
                    setAlgo={this.setAlgo}
                    onStart={this.addNumber}
                    onReset={this.onReset}
                />
                {/*<Details*/}
                {/*    algo={this.state.algo}*/}
                {/*/>*/}
                <CanvasSvg
                    leftMost = {this.state.leftMost}
                    rightMost = {this.state.rightMost}
                    algorithm = {this.props.algo}
                    time = {this.state.time}
                    N = {this.state.n}
                    vertices={this.state.vertices}
                    edges={this.state.edges}
                    current={this.state.current}
                    offset={this.state.offset}
                    reset = {this.state.reset}
                    animation_stop = {this.state.animation_stop}
                    nrFlag = {this.state.nrFlag}
                    redNumber = {this.state.redNumber}
                />
            </div>
        );
    }
}
function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}
export default Graph;